package com.xjk.date;

import com.xjk.string.StringUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 * 时间类型工具类
 */
public final class DateUtil{

    /**
     * 年-月-日 时《两位年》
     */
    public static final String PATTERN_MONITOR_TIME = "yy-MM-dd HH";

    /**
     * 年-月-日 时《四位年》
     */
    public static final String PATTERN_FULL_HOUR = "yyyy-MM-dd HH";

    /**
     * 24小时
     */
    public static final String HOUR = "HH";

    /**
     * 年-月-日
     */
    public static final String PATTERN_SIMPLE = "yyyy-MM-dd";

    /**
     * 年-月-日 时:分
     */
    public static final String PATTERN_MINUTES = "yyyy-MM-dd HH:mm";

    /**
     * 年-月-日 时:分:秒
     */
    public static final String PATTERN_NORMAL = "yyyy-MM-dd HH:mm:ss";

    /**
     * 年-月-日 时:分:秒 毫秒
     */
    public static final String PATTERN_FULL = "yyyy-MM-dd HH:mm:ss S";

    /**
     * 年月日时分秒毫秒
     */
    public static final String PATTERN_FULL_SIMPLE = "yyyyMMddHHmmss";

    /**
     * 年月日
     */
    public static final String PATTERN_FULL_DAY = "yyyyMMdd";

    /**
     * 月日年
     */
    public static final String PATTERN_MONTH_DAY = "MMddyy";

    /**
     * 日月年
     */
    public static final String PATTERN_REVERSE_DAY = "ddMMyyyy";

    /**
     * 表示没用过种格式
     */
    public static final String ORACLE_FORMAT = "YYYY-MM-DD HH24:MI:SS";

    /**
     * 年月日时分秒四位毫秒
     */
    public static final String SSSS = "yyyyMMddHHmmssSSSS";

    /**
     * 年月日时分秒三位毫秒
     */
    public static final String PATTERN_SSS = "yyyyMMddHHmmssSSS";

    public static final String PATTERN_FULL_TIME = "HHmmss";

    public static final String PATTERN_SIMPLE_TIME = "HH:mm:ss";

    public static final String PATTERN_SIMPLE_DATE = "yyMMdd";

    public static final String PATTERN_SIMPLE_TIME1 = "HH:mm.ss";

    public static final String PATTERN_SIMPLE_TIME2 = "yyyyMMdd HH:mm:ss";

    public static final String PATTEN_SIMPLE_TIMESS = "HHmmss-SSS";

    public static final String PATTEN_SIMPLE_HOURMIN = "HHmm";

    public static final String DATE_REGION_START_TIME = "startTime";

    public static final String DATE_REGION_END_TIME = "endTime";

    /**
     * 年月日时分
     */
    public static final String PATTERN_DAYMIN_SIMPLE = "yyyyMMddHHmm";

    public static final String PATTERN_SIMPLE_YEAR = "yyyy";

    public static final String PATTERN_SIMPLE_MONTH = "MM";

    public static final String PATTERN_SIMPLE_DAY = "dd";

    public static final String PATTERN_SIMPLE_HOUR = "HH";

    public static final String PATTERN_SIMPLE_MINTUNE = "mm";

    public static final String PATTERN_SIMPLE_SECOND = "ss";

    public static final String PATTERN_SIMPLE_MILLISECOND = "SSS";

    /**
     * 根据pattern格式，解析src日期字符串
     * 
     * @param src
     * @param pattern
     * @return
     * @throws ParseException
     * @Description:
     */
    public static Date parse(String src,String pattern) throws ParseException{
        SimpleDateFormat util = new SimpleDateFormat();
        util.applyPattern(pattern);
        return util.parse(src);
    }

    /**
     * 自动解析日期字符串 年-月-日 年-月-日 时:分:秒 年-月-日 时:分:秒 毫秒 其它格式抛出异常（）
     * 
     * @param src
     * @return
     * @Description:
     */
    public static Date parse(String src){
        SimpleDateFormat util = new SimpleDateFormat(PATTERN_SIMPLE);
        Date ret = null;
        if (!StringUtils.isEmpty(src)){
            util.applyPattern(PATTERN_NORMAL);
            try{
                ret = util.parse(src);
            }catch (ParseException e){}
            if (ret == null){
                try{
                    util.applyPattern(PATTERN_SIMPLE);
                    ret = util.parse(src);
                }catch (ParseException e){}
            }
            if (ret == null){
                try{
                    util.applyPattern(PATTERN_FULL);
                    ret = util.parse(src);
                }catch (ParseException e){}
            }
            if (ret == null){
                try{
                    util.applyPattern(PATTERN_FULL_SIMPLE);
                    ret = util.parse(src);
                }catch (ParseException e){}
            }
        }
        if (ret == null){
            throw new IllegalArgumentException("## cant parse to Date . not supported by default pattern: $" + src + "$");
        }
        return ret;
    }

    /**
     * 将时间数字解析成{@link java.util.Date}
     * 
     * @param timeMills
     * @return
     * @Description:
     */
    public static Date parse(Long timeMills){
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timeMills);
        // taobao 使用估计标准时间，北京时间需+8小时
        calendar.add(Calendar.HOUR_OF_DAY, 8);
        return calendar.getTime();
    }

    /**
     * 得到某一天的开始时间 清空时分秒毫秒 即为当天的00:00:00
     * 
     * @param date
     * @return
     * @Description:
     */
    public static Date getDayBegin(Date date){
        if (date == null){
            date = nowDate();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.clear(Calendar.HOUR_OF_DAY);
        cal.clear(Calendar.MINUTE);
        cal.clear(Calendar.SECOND);
        cal.clear(Calendar.MILLISECOND);
        return cal.getTime();
    }

    /**
     * 
     * @param date
     * @return
     * @Description:
     */
    public static Date getFirstDateOfWeek(Date date){
        Calendar cal = getCalByDate(date);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        return cal.getTime();
    }

    /**
     * 得到某一天的结束，清空时分秒，天数加1，减一秒钟，即为当天的23：59：59
     * 
     * @param date
     * @return
     * @Description:
     */
    public static Date getDayEnd(Date date){
        Date ret = getDayBegin(date);
        Calendar calendar = getCalByDate(ret);
        calendar.add(Calendar.DAY_OF_YEAR, 1);
        calendar.add(Calendar.SECOND, -1);
        return calendar.getTime();
    }

    /**
     * 根据pattern 格式化显示date
     * 
     * @param date
     * @param pattern
     * @return
     * @Description:
     */
    public static String formatDate(Date date,String pattern){
        if (date == null){
            return "";
        }
        SimpleDateFormat util = new SimpleDateFormat(pattern);
        String str = util.format(date);
        return str;
    }

    /**
     * 得到field的num时间 field为Calendar.YEAR|Calendar.MONTH|Calendar.DAY_OF_MONTH|....... num可为正可为负，为负表示往前
     * 
     * <pre>
     * example:
     *    1: DateUtil.addField('2015-04-10 18:00:00',{@link Calendar}.YEAR, 1)
     *             ----->result:'2016-04-10 18:00:00'
     *    2: DateUtil.addField('2015-04-10 18:00:00',{@link Calendar}.SECOND, -4)
     *             ----->result:'2015-04-10 17:59:56'
     * </pre>
     * 
     * @param date
     * @param field
     * @param num
     * @return
     * @Description:
     */
    public static Date addField(Date date,int field,int num){
        Calendar cal = getCalByDate(date);
        cal.add(field, num);
        return cal.getTime();
    }

    public static Date addMinutes(Date date,int minutes){
        return addField(date, Calendar.MINUTE, minutes);
    }

    public static Date addSeconds(Date date,int seconds){
        return addField(date, Calendar.SECOND, seconds);
    }

    public static Date addHours(Date date,int hours){
        return addField(date, Calendar.HOUR, hours);
    }

    /**
     * 清除分秒和毫秒
     * 
     * @param date
     * @return
     * @Description:
     */
    public static Date clearMinutesAndSeconds(Date date){
        if (null == date){
            throw new IllegalArgumentException();
        }
        Calendar calendar = getCalByDate(date);
        calendar.clear(Calendar.MINUTE);
        calendar.clear(Calendar.SECOND);
        calendar.clear(Calendar.MILLISECOND);
        return calendar.getTime();
    }

    /**
     * 清除秒和毫秒
     * 
     * @param date
     * @return
     */
    public static Date clearSeconds(Date date){
        if (null == date){
            throw new IllegalArgumentException();
        }
        Calendar calendar = getCalByDate(date);
        calendar.clear(Calendar.SECOND);
        calendar.clear(Calendar.MILLISECOND);
        return calendar.getTime();
    }

    /**
     * 获取当前时间String：yyyyMMddHHmmss
     * 
     * @return
     */
    public static String now(){
        return formatDate(Calendar.getInstance().getTime(), PATTERN_FULL_SIMPLE);
    }

    /**
     * 按dateFormat格式获取当前时间String
     * 
     * @param dateFormat
     * @return
     */
    public static String now(String dateFormat){
        return formatDate(Calendar.getInstance().getTime(), dateFormat);
    }

    /**
     * 获取当前时间Date
     * 
     * @return
     */
    public static Date nowDate(){
        return Calendar.getInstance().getTime();
    }

    /**
     * 取得世界时间
     * 
     * @param date
     * @return
     * @Description:
     */
    public static Date getUTC(Date date){
        // 取得本地时间：
        Calendar cal = Calendar.getInstance();
        // 取得时间偏移量：
        int zoneOffset = cal.get(Calendar.ZONE_OFFSET);
        // 取得夏令时差：
        int dstOffset = cal.get(Calendar.DST_OFFSET);
        // 定义新的日历时间
        Calendar dateCal = getCalByDate(date);
        // 消除偏移量
        dateCal.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        // 返回世界时间
        return dateCal.getTime();
    }

    public static String yesterday(){
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        return formatDate(cal.getTime(), PATTERN_FULL_DAY);
    }

    public static String day(){
        return formatDate(Calendar.getInstance().getTime(), PATTERN_FULL_DAY);
    }

    public static String ssss(){
        return formatDate(Calendar.getInstance().getTime(), SSSS);
    }

    public static String compare(Date beginTime,Date endTime){
        long l = endTime.getTime() - beginTime.getTime();
        long day = l / (24 * 60 * 60 * 1000);
        long hour = (l / (60 * 60 * 1000) - day * 24);
        long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long s = (l / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        return "" + day + "天" + hour + "小时" + min + "分" + s + "秒";
    }

    /** For creating xml dates. */
    private static ThreadLocal<DatatypeFactory> threadDatatypeFactory = new ThreadLocal<DatatypeFactory>();

    public static DatatypeFactory getDTF(){
        DatatypeFactory dtf = threadDatatypeFactory.get();
        if (dtf == null){
            try{
                dtf = DatatypeFactory.newInstance();
            }catch (Exception e){
                e.printStackTrace();
            }
            threadDatatypeFactory.set(dtf);
        }
        return dtf;
    }

    public static XMLGregorianCalendar geneXMLGregorianCalendar(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        DatatypeFactory df = getDTF();
        threadDatatypeFactory.remove();
        return df.newXMLGregorianCalendar(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), 0, cal.get(Calendar.ZONE_OFFSET));
    }

    public static XMLGregorianCalendar convertToXMLGregorianCalendar(Date date){
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        XMLGregorianCalendar gc = null;
        try{
            gc = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
        }catch (Exception e){

            e.printStackTrace();
        }
        return gc;
    }

    public static Date convertToDate(XMLGregorianCalendar cal) throws Exception{
        GregorianCalendar ca = cal.toGregorianCalendar();
        return ca.getTime();
    }

    /**
     * <pre>
     * delay为时分秒的格式，为24:00:00,这样就是将时间提前到一天 
     * 也可以分钟形式，123:00提前123分钟 依此类推
     * </pre>
     * 
     * @param endDate
     * @param delay
     * @return
     * @Description:
     */
    public static Date getDelayTimeByDate(Date primaryDate,String delay){
        Date date = new Date();
        if (primaryDate == null){
            primaryDate = new Date();
        }
        Calendar primaryCal = Calendar.getInstance();
        primaryCal.setTime(primaryDate);
        String[] delayArray = delay.split(":");
        List<String> delayList = Arrays.asList(delayArray);
        Collections.reverse(delayList);
        for (int i = 0; i < delayList.size(); i++){
            int single = Integer.parseInt(delayList.get(i));
            switch (i) {
                case 2:
                    primaryCal.add(Calendar.DAY_OF_YEAR, 0 - Math.abs(single));
                    break;
                case 1:
                    primaryCal.add(Calendar.MINUTE, 0 - Math.abs(single));
                    break;
                case 0:
                    primaryCal.add(Calendar.SECOND, 0 - Math.abs(single));
                    break;
                default:
                    break;
            }
        }
        return date;
    }

    /**
     * <pre>
     * 根据时间进行前移或后移
     * 根据delay的正负来判断前移还是后移
     * 
     * </pre>
     * 
     * @param endDate
     * @param delay
     * @return
     * @Description:
     */
    public static Date getDelayTimeByDate(Date primaryDate,long delay){
        if (primaryDate == null){
            primaryDate = new Date();
        }
        Calendar primaryCal = Calendar.getInstance();
        primaryCal.setTime(primaryDate);
        Long s = primaryDate.getTime() + delay;
        primaryCal.setTimeInMillis(s);
        return primaryCal.getTime();
    }

    /**
     * 设置 _c 时分秒为0
     */
    public static Calendar roundCalendar(Calendar c){
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c;
    }

    /**
     * 设置 _d 的时分秒为0
     */
    public static Date roundDate(Date d){
        Calendar c = Calendar.getInstance();
        c.setTime(d);
        return roundCalendar(c).getTime();
    }

    /**
     * 指定timePattern的时间的delay范围(正负之分)
     * 
     * @param endDate
     * @param timePattern
     * @param delay
     * @return
     * @throws ParseException
     * @Description:
     */
    public static Map<String, Date> getRegionTime(Date date,String timePattern,long delay) throws ParseException{
        Map<String, Date> dateMap = new HashMap<String, Date>();
        Date dateTime1 = getRegularTimeByDate(date, timePattern);
        Date dateTime2 = getDelayTimeByDate(dateTime1, delay);
        // 设置起始时间与结束时间
        if (dateTime1.after(dateTime2)){
            dateMap.put(DATE_REGION_START_TIME, dateTime2);
            dateMap.put(DATE_REGION_END_TIME, dateTime1);
        }else{
            dateMap.put(DATE_REGION_START_TIME, dateTime1);
            dateMap.put(DATE_REGION_END_TIME, dateTime2);
        }
        return dateMap;
    }

    /**
     * 获取指定的时分秒
     * 
     * @param date
     * @param regular
     * @param delay
     * @return
     * @throws ParseException
     * @Description:
     */
    private static Date getRegularTimeByDate(Date date,String regular) throws ParseException{
        // 指定的时间只有时分秒
        Date regularDate = DateUtil.parse(regular, "HH:mm:ss");
        Calendar dateCal = Calendar.getInstance();
        dateCal.setTime(regularDate);
        // 参数时间
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 将参数时间中的时分秒设置成指定的时间
        cal.set(Calendar.HOUR_OF_DAY, dateCal.get(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, dateCal.get(Calendar.MINUTE));
        cal.set(Calendar.SECOND, dateCal.get(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, 0);
        // 返回指定时间
        return cal.getTime();
    }

    private static Calendar getCalByDate(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal;
    }

}
